package gov.nasa.arc.mct.plot.settings; import gov.nasa.arc.mct.plot.settings.PlotConstants.AxisBounds; import gov.nasa.arc.mct.plot.settings.PlotConstants.AxisType; import java.awt.Color; import java.awt.Component; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.NumberFormat; import java.util.ResourceBundle; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTextField; import javax.swing.border.LineBorder; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.DocumentFilter; import javax.swing.text.InternationalFormatter; public class PlotBehaviorPanel extends PlotSettingsPanel { // Access bundle file where externalized strings are defined. private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("gov.nasa.arc.mct.fastplot.view.Bundle"); private static final int BEHAVIOR_CELLS_X_PADDING = 18; private static final int INDENTATION_SEMI_FIXED_CHECKBOX = 16; private static final int NONTIME_TITLE_SPACING = 0; private static final int PADDING_COLUMNS = 3; /* * Plot Behavior panel controls */ private JRadioButton nonTimeMinAutoAdjustMode; private JRadioButton nonTimeMaxAutoAdjustMode; private JRadioButton nonTimeMinFixedMode; private JRadioButton nonTimeMaxFixedMode; private JCheckBox nonTimeMinSemiFixedMode; private JCheckBox nonTimeMaxSemiFixedMode; private JTextField nonTimeMinPadding; private JTextField nonTimeMaxPadding; private JCheckBox pinTimeAxis; private JRadioButton timeJumpMode; private JRadioButton timeScrunchMode; private JTextField timeJumpPadding; private JTextField timeScrunchPadding; private JLabel behaviorTimeAxisLetter; private JLabel behaviorNonTimeAxisLetter; public PlotBehaviorPanel() { setLayout(new GridBagLayout()); JPanel modePanel = new JPanel(new GridLayout(1, 1)); JButton bMode = new JButton(BUNDLE.getString("Mode.label")); bMode.setAlignmentY(CENTER_ALIGNMENT); modePanel.add(bMode); JPanel minPanel = new JPanel(new GridLayout(1, 1)); JLabel bMin = new JLabel(BUNDLE.getString("Min.label")); bMin.setHorizontalAlignment(JLabel.CENTER); minPanel.add(bMin); JPanel maxPanel = new JPanel(new GridLayout(1, 1)); maxPanel.add(new JLabel(BUNDLE.getString("Max.label"))); GridLinedPanel timeAxisPanel = createGriddedTimeAxisPanel(); GridLinedPanel nonTimeAxisPanel = createGriddedNonTimeAxisPanel(); behaviorTimeAxisLetter = new JLabel("_"); JPanel behaviorTimeTitlePanel = new JPanel(); behaviorTimeTitlePanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, NONTIME_TITLE_SPACING)); behaviorTimeTitlePanel.add(new JLabel(BUNDLE.getString("TimeAxis.label") + " (")); behaviorTimeTitlePanel.add(behaviorTimeAxisLetter); behaviorTimeTitlePanel.add(new JLabel("):")); pinTimeAxis = new JCheckBox(BUNDLE.getString("PinTimeAxis.label")); behaviorTimeTitlePanel.add(pinTimeAxis); behaviorNonTimeAxisLetter = new JLabel("_"); JPanel behaviorNonTimeTitlePanel = new JPanel(); behaviorNonTimeTitlePanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, NONTIME_TITLE_SPACING)); behaviorNonTimeTitlePanel.add(new JLabel(BUNDLE.getString("NonTimeAxis.label") + " (")); behaviorNonTimeTitlePanel.add(behaviorNonTimeAxisLetter); behaviorNonTimeTitlePanel.add(new JLabel("):")); GridBagConstraints gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.gridx = 0; gbc.gridy = 0; gbc.insets = new Insets(6, 0, 0, 0); add(behaviorTimeTitlePanel, gbc); gbc.gridy++; gbc.insets = new Insets(0, 0, 0, 0); add(timeAxisPanel, gbc); gbc.gridy++; gbc.insets = new Insets(6, 0, 0, 0); add(behaviorNonTimeTitlePanel, gbc); gbc.gridy++; gbc.insets = new Insets(0, 0, 0, 0); add(nonTimeAxisPanel, gbc); // Instrument setName("plotBehavior"); modePanel.setName("modePanel"); bMode.setName("bMode"); minPanel.setName("minPanel"); bMin.setName("bMin"); maxPanel.setName("maxPanel"); timeAxisPanel.setName("timeAxisPanel"); nonTimeAxisPanel.setName("nonTimeAxisPanel"); behaviorTimeAxisLetter.setName("behaviorTimeAxisLetter"); behaviorNonTimeAxisLetter.setName("behaviorNonTimeAxisLetter"); } // The Time Axis table within the Plot Behavior area private GridLinedPanel createGriddedTimeAxisPanel() { JLabel titleMode = new JLabel(BUNDLE.getString("Mode.label")); JLabel titleMin = new JLabel(BUNDLE.getString("Min.label")); JLabel titleMinPadding = new JLabel(BUNDLE.getString("Min.label")); JLabel titleMax = new JLabel(BUNDLE.getString("Max.label")); JLabel titleMaxPadding = new JLabel(BUNDLE.getString("Max.label")); JLabel titleSpan = new JLabel(BUNDLE.getString("Span.label")); JLabel titleMax_Min = new JLabel("(" + BUNDLE.getString("MaxMinusMin.label") +")"); JPanel titlePanelSpan = new JPanel(); titlePanelSpan.setLayout(new BoxLayout(titlePanelSpan, BoxLayout.Y_AXIS)); titlePanelSpan.add(titleSpan); titlePanelSpan.add(titleMax_Min); titleSpan.setAlignmentX(Component.CENTER_ALIGNMENT); titleMax_Min.setAlignmentX(Component.CENTER_ALIGNMENT); JLabel titlePaddingOnRedraw = new JLabel(BUNDLE.getString("PaddingOnRedraw.label")); setFontToBold(titleMode); setFontToBold(titleMin); setFontToBold(titleMax); setFontToBold(titleMinPadding); setFontToBold(titleMaxPadding); setFontToBold(titlePaddingOnRedraw); setFontToBold(titleSpan); setFontToBold(titleMax_Min); timeJumpMode = new JRadioButton(BUNDLE.getString("Jump.label")); timeScrunchMode = new JRadioButton(BUNDLE.getString("Scrunch.label")); JPanel timeJumpModePanel = new JPanel(); timeJumpModePanel.add(timeJumpMode); JPanel timeScrunchModePanel = new JPanel(); timeScrunchModePanel.add(timeScrunchMode); ButtonGroup modeGroup = new ButtonGroup(); modeGroup.add(timeJumpMode); modeGroup.add(timeScrunchMode); timeJumpMode.setSelected(true); timeJumpPadding = createPaddingTextField(AxisType.TIME_IN_JUMP_MODE, AxisBounds.MAX); timeScrunchPadding = createPaddingTextField(AxisType.TIME_IN_SCRUNCH_MODE, AxisBounds.MAX); JPanel timeJumpPaddingPanel = new JPanel(); timeJumpPaddingPanel.add(timeJumpPadding); timeJumpPaddingPanel.add(new JLabel(BUNDLE.getString("Percent.label"))); JPanel timeScrunchPaddingPanel = new JPanel(); timeScrunchPaddingPanel.add(timeScrunchPadding); timeScrunchPaddingPanel.add(new JLabel(BUNDLE.getString("Percent.label"))); GridLinedPanel griddedPanel = new GridLinedPanel(); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridwidth = 1; gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1; gbc.weighty = 1; gbc.ipadx = BEHAVIOR_CELLS_X_PADDING; gbc.gridheight = 2; griddedPanel.setGBC(gbc); // Title row A int row = 0; griddedPanel.addCell(titleMode, 0, row); griddedPanel.addCell(titleMin, 1, row); griddedPanel.addCell(titleMax, 2, row); gbc.gridheight = 2; griddedPanel.addCell(titlePanelSpan, 3, row); gbc.gridheight = 1; gbc.gridwidth = 2; griddedPanel.addCell(titlePaddingOnRedraw, 4, row); gbc.gridwidth = 1; // Title row B - only two entries row++; griddedPanel.addCell(titleMinPadding, 4, row); griddedPanel.addCell(titleMaxPadding, 5, row); // Row 1 row++; griddedPanel.addCell(timeJumpModePanel, 0, row, GridBagConstraints.WEST); griddedPanel.addCell(new JLabel(BUNDLE.getString("AutoAdjusts.label")), 1, row); griddedPanel.addCell(new JLabel(BUNDLE.getString("AutoAdjusts.label")), 2, row); griddedPanel.addCell(new JLabel(BUNDLE.getString("Fixed.label")), 3, row); griddedPanel.addCell(new JLabel(BUNDLE.getString("Dash.label")), 4, row); griddedPanel.addCell(timeJumpPaddingPanel, 5, row); // Row 2 row++; griddedPanel.addCell(timeScrunchModePanel, 0, row, GridBagConstraints.WEST); griddedPanel.addCell(new JLabel(BUNDLE.getString("Fixed.label")), 1, row); griddedPanel.addCell(new JLabel(BUNDLE.getString("AutoAdjusts.label")), 2, row); griddedPanel.addCell(new JLabel(BUNDLE.getString("AutoAdjusts.label")), 3, row); griddedPanel.addCell(new JLabel(BUNDLE.getString("Dash.label")), 4, row); griddedPanel.addCell(timeScrunchPaddingPanel, 5, row); return griddedPanel; } // The Non-Time Axis table within the Plot Behavior panel private GridLinedPanel createGriddedNonTimeAxisPanel() { JLabel titleMin = new JLabel(BUNDLE.getString("Min.label")); JLabel titleMax = new JLabel(BUNDLE.getString("Max.label")); JLabel titlePadding = new JLabel(BUNDLE.getString("Padding.label")); JLabel titleMinPadding = new JLabel(BUNDLE.getString("Min.label")); JLabel titleMaxPadding = new JLabel(BUNDLE.getString("Max.label")); setFontToBold(titleMin); setFontToBold(titleMax); setFontToBold(titlePadding); setFontToBold(titleMinPadding); setFontToBold(titleMaxPadding); nonTimeMinAutoAdjustMode = new JRadioButton(BUNDLE.getString("AutoAdjusts.label")); nonTimeMaxAutoAdjustMode = new JRadioButton(BUNDLE.getString("AutoAdjusts.label")); nonTimeMinFixedMode = new JRadioButton(BUNDLE.getString("Fixed.label")); nonTimeMaxFixedMode = new JRadioButton(BUNDLE.getString("Fixed.label")); JPanel nonTimeMinAutoAdjustModePanel = new JPanel(); nonTimeMinAutoAdjustModePanel.add(nonTimeMinAutoAdjustMode); JPanel nonTimeMaxAutoAdjustModePanel = new JPanel(); nonTimeMaxAutoAdjustModePanel.add(nonTimeMaxAutoAdjustMode); JPanel nonTimeMinFixedModePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0)); nonTimeMinFixedModePanel.add(nonTimeMinFixedMode); JPanel nonTimeMaxFixedModePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0)); nonTimeMaxFixedModePanel.add(nonTimeMaxFixedMode); nonTimeMinAutoAdjustMode.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { nonTimeMinSemiFixedMode.setEnabled(false); nonTimeMinSemiFixedMode.setSelected(false); } }); nonTimeMinFixedMode.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if(nonTimeMinFixedMode.isSelected()) { nonTimeMinSemiFixedMode.setEnabled(true); } else { nonTimeMinSemiFixedMode.setEnabled(false); nonTimeMinSemiFixedMode.setSelected(false); } } }); nonTimeMaxAutoAdjustMode.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { nonTimeMaxSemiFixedMode.setEnabled(false); nonTimeMaxSemiFixedMode.setSelected(false); } }); nonTimeMaxFixedMode.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if(nonTimeMaxFixedMode.isSelected()) { nonTimeMaxSemiFixedMode.setEnabled(true); } else { nonTimeMaxSemiFixedMode.setEnabled(false); nonTimeMaxSemiFixedMode.setSelected(false); } } }); nonTimeMinAutoAdjustMode.setSelected(true); nonTimeMaxAutoAdjustMode.setSelected(true); ButtonGroup minGroup = new ButtonGroup(); minGroup.add(nonTimeMinAutoAdjustMode); minGroup.add(nonTimeMinFixedMode); ButtonGroup maxGroup = new ButtonGroup(); maxGroup.add(nonTimeMaxAutoAdjustMode); maxGroup.add(nonTimeMaxFixedMode); nonTimeMinSemiFixedMode = new JCheckBox(BUNDLE.getString("SemiFixed.label")); nonTimeMaxSemiFixedMode = new JCheckBox(BUNDLE.getString("SemiFixed.label")); JPanel nonTimeMinSemiFixedModePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 2)); JPanel nonTimeMaxSemiFixedModePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 2)); nonTimeMinSemiFixedModePanel.add(nonTimeMinSemiFixedMode); nonTimeMaxSemiFixedModePanel.add(nonTimeMaxSemiFixedMode); nonTimeMinSemiFixedMode.setEnabled(false); nonTimeMaxSemiFixedMode.setEnabled(false); nonTimeMinPadding = createPaddingTextField(AxisType.NON_TIME, AxisBounds.MIN); nonTimeMaxPadding = createPaddingTextField(AxisType.NON_TIME, AxisBounds.MAX); JPanel nonTimeMinPaddingPanel = new JPanel(); nonTimeMinPaddingPanel.add(nonTimeMinPadding); nonTimeMinPaddingPanel.add(new JLabel(BUNDLE.getString("Percent.label"))); JPanel nonTimeMaxPaddingPanel = new JPanel(); nonTimeMaxPaddingPanel.add(nonTimeMaxPadding); nonTimeMaxPaddingPanel.add(new JLabel(BUNDLE.getString("Percent.label"))); JPanel nonTimeMins = new JPanel(); nonTimeMins.setLayout(new GridBagLayout()); GridBagConstraints gbc0 = new GridBagConstraints(); gbc0.gridy = 0; gbc0.anchor = GridBagConstraints.WEST; nonTimeMins.add(nonTimeMinAutoAdjustModePanel, gbc0); gbc0.gridy = 1; nonTimeMins.add(nonTimeMinFixedModePanel, gbc0); gbc0.gridy = 2; gbc0.insets = new Insets(0, INDENTATION_SEMI_FIXED_CHECKBOX, 0, 0); nonTimeMins.add(nonTimeMinSemiFixedModePanel, gbc0); JPanel nonTimeMaxs = new JPanel(); nonTimeMaxs.setLayout(new GridBagLayout()); GridBagConstraints gbc1 = new GridBagConstraints(); gbc1.gridy = 0; gbc1.anchor = GridBagConstraints.WEST; nonTimeMaxs.add(nonTimeMaxAutoAdjustModePanel, gbc1); gbc1.gridy = 1; nonTimeMaxs.add(nonTimeMaxFixedModePanel, gbc1); gbc1.gridy = 2; gbc1.insets = new Insets(0, INDENTATION_SEMI_FIXED_CHECKBOX, 0, 0); nonTimeMaxs.add(nonTimeMaxSemiFixedModePanel, gbc1); GridLinedPanel griddedPanel = new GridLinedPanel(); GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1; gbc.weighty = 1; gbc.ipadx = BEHAVIOR_CELLS_X_PADDING; griddedPanel.setGBC(gbc); // Title row A int row = 0; gbc.gridwidth = 1; gbc.gridheight = 2; // First 2 titles are 2 rows high griddedPanel.addCell(titleMin, 1, row); griddedPanel.addCell(titleMax, 2, row); gbc.gridwidth = 2; // "Padding" spans 2 columns, 1 row high gbc.gridheight = 1; griddedPanel.addCell(titlePadding, 3, row); gbc.gridwidth = 1; // Title row B - only 2 cells occupied row++; griddedPanel.addCell(titleMinPadding, 3, row); griddedPanel.addCell(titleMaxPadding, 4, row); // Row 1 row++; griddedPanel.addCell(nonTimeMins, 1, row, GridBagConstraints.WEST); griddedPanel.addCell(nonTimeMaxs, 2, row, GridBagConstraints.WEST); griddedPanel.addCell(nonTimeMinPaddingPanel, 3, row); griddedPanel.addCell(nonTimeMaxPaddingPanel, 4, row); // Instrument nonTimeMins.setName("nonTimeMins"); nonTimeMaxs.setName("nonTimeMaxs"); return griddedPanel; } @SuppressWarnings("serial") private JTextField createPaddingTextField(AxisType axisType, AxisBounds bound) { final JFormattedTextField tField = new JFormattedTextField(new InternationalFormatter( NumberFormat.getIntegerInstance()) { protected DocumentFilter getDocumentFilter() { return filter; } private DocumentFilter filter = new PaddingFilter(); }); tField.setColumns(PADDING_COLUMNS); tField.setHorizontalAlignment(JTextField.RIGHT); if (bound.equals(AxisBounds.MIN)) { tField.setText(axisType.getMinimumDefaultPaddingAsText()); } else { tField.setText(axisType.getMaximumDefaultPaddingAsText()); } tField.addAncestorListener(new AncestorListener() { @Override public void ancestorAdded(AncestorEvent event) { tField.selectAll(); tField.removeAncestorListener(this); } @Override public void ancestorMoved(AncestorEvent event) { } @Override public void ancestorRemoved(AncestorEvent event) { } }); return tField; } private void setFontToBold(JLabel item) { item.setFont(item.getFont().deriveFont(Font.BOLD)); } /* * This filter blocks non-numeric characters from being entered in the padding fields */ class PaddingFilter extends DocumentFilter { private StringBuilder insertBuilder; private StringBuilder replaceBuilder; @Override public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException { insertBuilder = new StringBuilder(string); for (int k = insertBuilder.length() - 1; k >= 0; k--) { int cp = insertBuilder.codePointAt(k); if (! Character.isDigit(cp)) { insertBuilder.deleteCharAt(k); if (Character.isSupplementaryCodePoint(cp)) { k--; insertBuilder.deleteCharAt(k); } } } if (insertBuilder.length() + fb.getDocument().getLength() < 3 && insertBuilder.length() + fb.getDocument().getLength() > 0) { super.insertString(fb, offset, insertBuilder.toString(), attr); } } @Override public void replace(FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException { replaceBuilder = new StringBuilder(string); for (int k = replaceBuilder.length() - 1; k >= 0; k--) { int cp = replaceBuilder.codePointAt(k); if (! Character.isDigit(cp)) { replaceBuilder.deleteCharAt(k); if (Character.isSupplementaryCodePoint(cp)) { k--; replaceBuilder.deleteCharAt(k); } } } if ((replaceBuilder.length() - length + fb.getDocument().getLength()) < 3) { if ((replaceBuilder.length() - length + fb.getDocument().getLength()) == 0) { super.replace(fb, offset, length, "0", attr); } else { super.replace(fb, offset, length, replaceBuilder.toString(), attr); } } } @Override public void remove(FilterBypass fb, int offset, int length) throws BadLocationException { if (fb.getDocument().getLength() - length >= 1) { super.remove(fb, offset, length); } else { super.replace(fb, 0, fb.getDocument().getLength(), "0", null); } } StringBuilder getInsertBuilder() { return insertBuilder; } StringBuilder getReplaceBuilder() { return replaceBuilder; } } private static class GridLinedPanel extends JPanel { private static final long serialVersionUID = -1227455333903006294L; private GridBagConstraints wrapGbc; public GridLinedPanel() { setLayout(new GridBagLayout()); setBorder(BorderFactory.createLineBorder(Color.gray)); } void setGBC(GridBagConstraints inputGbc) { wrapGbc = inputGbc; } // Wrap each added ui control in a JPanel with a border void addCell(JLabel uiControl, int xPosition, int yPosition) { uiControl.setHorizontalAlignment(JLabel.CENTER); wrapControlInPanel(uiControl, xPosition, yPosition); } // Wrap each added ui control in a JPanel with a border void addCell(JPanel uiControl, int xPosition, int yPosition) { wrapControlInPanel(uiControl, xPosition, yPosition); } private void wrapControlInPanel(JComponent uiControl, int xPosition, int yPosition) { JPanel wrapperPanel = new JPanel(); wrapperPanel.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); wrapperPanel.add(uiControl, gbc); wrapGbc.gridx = xPosition; wrapGbc.gridy = yPosition; wrapperPanel.setBorder(new LineBorder(Color.lightGray)); add(wrapperPanel, wrapGbc); } private void addCell(JComponent uiControl, int xPosition, int yPosition, int alignment) { JPanel wrapperPanel = new JPanel(new GridBagLayout()); wrapperPanel.setBorder(new LineBorder(Color.lightGray)); GridBagConstraints gbc = new GridBagConstraints(); if (alignment == GridBagConstraints.WEST) { gbc.weightx = 1; gbc.anchor = GridBagConstraints.WEST; } wrapperPanel.add(uiControl, gbc); wrapGbc.gridx = xPosition; wrapGbc.gridy = yPosition; add(wrapperPanel, wrapGbc); } } }